//    Copyright (C) Kherty.  All rights reserved.
using System;
using System.Diagnostics.Contracts;

namespace OpenLS.Spreadsheet.Formats.Biff.Records
{
    internal class RowRecord : WorksheetLevelRecord
    {
        private ushort _colMac;
        private ushort _colMic;
        private int _dummyXfId;
        private bool _fCollapsed;
        private bool _fExAsc;
        private bool _fExDes;
        private bool _fGhostDirty;
        private bool _fPhonetic;
        private bool _fUnsynced;
        private double? _height;
        private ushort _index;
        private bool _isHidden;
        private byte _outlineLevel;
        private ushort _reserved1;
        private ushort _unused1;
        private bool _unused2;
        private int? _xfId;
        private uint reserved3;

        public RowRecord(Row row)
        {
            _index = (ushort) row.Index;
            if (row.CellCount > 0)
            {
                _colMic = (ushort) Enumerable.Min(row.GetCells(), c => c.Column.Index);
                _colMac = (ushort) (Enumerable.Max(row.GetCells(), c => c.Column.Index) + 1);
            }
            var rowTables =
                Enumerable.ToList(Enumerable.Where(row.Worksheet.Tables,
                                                   t =>
                                                   t.Range.Row <= row.Index +1 &&
                                                   t.Range.Row + t.Range.RowSpan - 1 >= row.Index));
            if (rowTables.Count > 0)
            {
                if (row.CellCount == 0)
                {
                    _colMic = ushort.MaxValue;
                    _colMac = ushort.MinValue;
                }
                _colMic = Math.Min(_colMic, (ushort)Enumerable.Min(rowTables, t => t.Range.Column));
                _colMac = Math.Max(_colMac, (ushort)Enumerable.Max(rowTables, t => t.Range.Column + t.Range.ColumnSpan ));
            }
            if (row.Height != null)
            {
                _height = row.Height.GetValueOrDefault(20);
                _fUnsynced = true;
            }
            else
            {
                _height = row.Worksheet.DefaultRowHeight;
            }
            _fCollapsed = row.IsCollapsed;
            //    if (fCollapsed)
            //       isHidden = true;
            _isHidden = row.IsHidden;
            _outlineLevel = (byte) row.OutlineLevel;
        }

        public RowRecord()
        {
        }

        public int Index
        {
            get { return _index; }
        }

        public double? Height
        {
            get { return _height; }
        }

        internal override BiffRecordType RecordType
        {
            get { return BiffRecordType.Row; }
        }

        private uint Flags
        {
            get
            {
                uint result = reserved3;
                result |= _outlineLevel;
                if (_fCollapsed)
                    result |= 0x00000010;
                if (_isHidden)
                    result |= 0x00000020;
                if (_fUnsynced)
                    result |= 0x00000040;
                if (_fGhostDirty)
                    result |= 0x00000080;
                if (_xfId != null)
                {
                    result |= 0x00000080;
                    result |= (uint) _xfId << 16;
                }
                else
                {
                    result |= (uint) _dummyXfId << 16;
                }
               // result |= 0x000000100;
                if (_fExAsc)
                    result |= 0x10000000;
                if (_fExDes)
                    result |= 0x20000000;
                if (_fPhonetic)
                    result |= 0x40000000;
                if (_unused2)
                    result |= 0x80000000;
                return result;
            }
        }


        internal override void WriteContent(BiffWriterWorkbookContext context)
        {
            context.Write(_index);
            context.Write(_colMic);
            context.Write(_colMac);
            ushort u = 0;
            if (_height != null)
            {
                u |= (ushort) (_height.GetValueOrDefault(0)*20*3/4);
            }
            else
            {
                u = 0x8000;
            }
            context.Write(u);
            context.Write(_reserved1);
            context.Write(_unused1);
            context.Write(Flags);
        }

        protected override void ReadContent(BiffReaderContext context, int length)
        {
            _index = context.ReadUInt16();
            _colMic = context.ReadUInt16();
            _colMac = context.ReadUInt16();
            ushort miyRw = context.ReadUInt16();
            int i = (miyRw & 0x8000);
            if (i == 0)
                _height = ((double) (miyRw & 0x7FFF))/20/3*4;
            _reserved1 = context.ReadUInt16(); //\\ not used;
            _unused1 = context.ReadUInt16();
            uint flags = context.ReadUInt32();
            _outlineLevel = (byte) (flags & 0x00000007);
            _fCollapsed = (flags & 0x00000010) != 0;
            _isHidden = (flags & 0x00000020) != 0;
            _fUnsynced = (flags & 0x00000040) != 0;
            _fGhostDirty = (flags & 0x00000080) != 0;
            reserved3 = flags & 0x0000FF00;
            bool hasExplicitDefaultFormat = (flags & 0x00000080) != 0;
            if (hasExplicitDefaultFormat)
                _xfId = (int) ((flags & 0x0FFF0000) >> 16);
            else
            {
                _dummyXfId = (int) ((flags & 0x0FFF0000) >> 16);
            }
            _fExAsc = (flags & 0x10000000) != 0;
            _fExDes = (flags & 0x20000000) != 0;
            _fPhonetic = (flags & 0x40000000) != 0;
            _unused2 = (flags & 0x80000000) != 0;
            Contract.Assert(Flags == flags);
        }

        internal override void Apply(BiffReaderWorksheetContext context)
        {
            Row r = context.Worksheet.Rows[Index];
            r.AdviseMinMax(this._colMic, this._colMac);
            if (Height != null)
                r.Height = Height;
            //\\todo r.OutlineLevel = outlineLevel;
            r.IsVisible = !_isHidden;
            if (_xfId != null)
                r.SetFormattingRecord(context.WorkbookContext.GetCellFormattingRecord(_xfId.Value));
            if (context.DefaultRowHeight != Height)
                r.Height = Height;
            context.RowGroupStack.ApplyOutlineLevel(r, r, _outlineLevel, !_isHidden, _fCollapsed);
        }
    }
}